package org.xq.softcup.mq.util;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
@Slf4j
public class BasicJsonwriter {

    private static final String STR_SLASH = "\"";
    private static final String STR_SLASH_STR = "\":";
    private static final String STR_COMMA = ",";
    private static final String STR_OBJECT_LEFT = "{";
    private static final String STR_OBJECT_RIGHT = "}";
    private static final String STR_ARRAY_LEFT = "[";
    private static final String STR_ARRAY_RIGHT = "]";
    private static final Map<String, Field[]> cacheFields = new HashMap();

    public String toJson(Object object)
    {
        StringBuilder json = new StringBuilder();
        try
        {
            writeObjItem(null, object, json);
        }
        catch (Exception e)
        {
            log.error(e.getMessage(), e);
        }
        String str = json.toString();
        if (str.contains("\n")) {
            str = str.replaceAll("\\n", "\\\\n");
        }
        if (str.contains("\t")) {
            str = str.replaceAll("\\t", "\\\\t");
        }
        if (str.contains("\r")) {
            str = str.replaceAll("\\r", "\\\\r");
        }
        return str;
    }

    private void writeObjItem(String key, Object value, StringBuilder json)
    {
        if (key != null) {
            json.append("\"").append(key).append("\":");
        }
        if (value == null)
        {
            json.append("null");
        }
        else if (((value instanceof String)) || ((value instanceof Byte)) || ((value instanceof CharSequence)))
        {
            json.append("\"").append(value.toString()).append("\"");
        }
        else if (((value instanceof Boolean)) || ((value instanceof Short)) || ((value instanceof Integer)) || ((value instanceof Long)) || ((value instanceof Float)) || ((value instanceof Double)))
        {
            json.append(value);
        }
        else if (((value instanceof Object[])) || ((value instanceof Collection)))
        {
            Collection valueColl = null;
            if ((value instanceof Object[]))
            {
                Object[] valueArr = (Object[])value;
                valueColl = Arrays.asList(valueArr);
            }
            else if ((value instanceof Collection))
            {
                valueColl = (Collection)value;
            }
            json.append("[");
            if (valueColl.size() > 0)
            {
                for (Object obj : valueColl)
                {
                    writeObjItem(null, obj, json);
                    json.append(",");
                }
                json.delete(json.length() - 1, json.length());
            }
            json.append("]");
        }
        else if ((value instanceof Map))
        {
            Map<?, ?> valueMap = (Map)value;

            json.append("{");
            if (!valueMap.isEmpty())
            {
                Set<?> keys = valueMap.keySet();
                for (Object valueMapItemKey : keys)
                {
                    writeObjItem(valueMapItemKey.toString(), valueMap.get(valueMapItemKey), json);
                    json.append(",");
                }
                json.delete(json.length() - 1, json.length());
            }
            json.append("}");
        }
        else
        {
            json.append("{");
            Field[] fields = getDeclaredFields(value.getClass());
            if (fields.length > 0)
            {
                for (Field field : fields)
                {
                    Object fieldObj = getFieldObject(field, value);
                    writeObjItem(field.getName(), fieldObj, json);
                    json.append(",");
                }
                json.delete(json.length() - 1, json.length());
            }
            json.append("}");
        }
    }

    public synchronized Field[] getDeclaredFields(Class<?> clazz)
    {
        String cacheKey = clazz.getName();
        if (cacheFields.containsKey(cacheKey)) {
            return (Field[])cacheFields.get(cacheKey);
        }
        Field[] fields = getAllDeclaredFields(clazz);
        cacheFields.put(cacheKey, fields);
        return fields;
    }

    private Field[] getAllDeclaredFields(Class<?> clazz)
    {
        List<Field> list = new ArrayList();
        Class<?> current = clazz;
        while ((current != null) && (current != Object.class))
        {
            Field[] fields = current.getDeclaredFields();
            for (Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    list.add(field);
                }
            }
            current = current.getSuperclass();
        }
        return (Field[])list.toArray(new Field[list.size()]);
    }

    private synchronized Object getFieldObject(Field field, Object obj)
    {
        try
        {
            field.setAccessible(true);
            return field.get(obj);
        }
        catch (IllegalArgumentException|IllegalAccessException e)
        {
            log.error(e.getMessage(), e);
            return null;
        }
        finally
        {
            field.setAccessible(false);
        }
    }
}
